#region imported Namespaces
using System;
using System.Data;
using System.Data.SqlClient;

using DataAccess = PHSRAG.Utility.DataAccess;
using SplitsConstants = PHSRAG.Insight21.Personnel.Constants.DistributionSplitsConstants;
using SalaryDistribConstants = PHSRAG.Insight21.Personnel.Constants.SalaryDistributionsConstants;
#endregion

namespace PHSRAG.Insight21.Personnel
{
	#region SalaryDistribution Class
	/// <summary>
	/// The SalaryDistribution is and abstract class and is the facade over the details for
	/// a single salary distribution.It will also hold the distribution splits which are 
	/// associated with this distribution.
	/// </summary>
	public abstract class SalaryDistribution
	{
		#region Instance Variables (Private)
		private DistributionSplits splits;
		#endregion
		
		#region Instance variables (Protected)
		///<summary>Instance to contain a single row of salary distribution data</summary>
		protected DataRow distribRow;
		
		///<summary>Intance to contain the sql param array for add/edit/delete
		///This is maintained in the state to facilitate/ease the process of
		///building the sqlParam array</summary>
		protected SqlParameter[] sqlParams;
		#endregion

		#region Properties
		/// <summary>
		/// Get the ID of the salary distribution
		/// </summary>
		public int DistributionID
		{
			get
			{
				return (int)distribRow[SalaryDistribConstants.DistributionIDColumnName];
			}
		}
		/// <summary>
		/// Get/Set the Employee Job Map Id to which this salary distribution is associated to
		/// </summary>
		public int EmployeeJobMapID
		{
			get
			{
				return (int)distribRow[SalaryDistribConstants.EmployeeJobMapIDColumnName];
			}
			set
			{
				distribRow[SalaryDistribConstants.EmployeeJobMapIDColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set the annual rate for the salary distribution
		/// Return 0 if no annual rate is available
		/// </summary>
		public decimal AnnualRate
		{
			get
			{
				object annualRate = distribRow[SalaryDistribConstants.AnnualRateColumnName];
				return (annualRate==DBNull.Value)?0:(decimal)annualRate;
			}
			set
			{
				distribRow[SalaryDistribConstants.AnnualRateColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set the comment given for this salary distribution
		/// Return an empty string if there is no comment is given for the distribution
		/// </summary>
		public string Comment
		{
			get
			{
				object comment = distribRow[SalaryDistribConstants.CommentColumnName];
				return (comment==DBNull.Value)?string.Empty:comment.ToString();
			}
			set
			{
				distribRow[SalaryDistribConstants.CommentColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set the salary distribution effective date
		/// Return an empty string if there is no effective date for the salary distribution
		/// </summary>
		public string EffectiveDate
		{
			get
			{
				object effectiveDate = distribRow[SalaryDistribConstants.EffectiveDateColumnName];
				return (effectiveDate==DBNull.Value)?
					string.Empty:((DateTime)effectiveDate).ToString("MM/dd/yyyy");
			}
			set
			{
				distribRow[SalaryDistribConstants.EffectiveDateColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set the salary distribution expiration date
		/// Return an empty string if there is no expiration date for the salary distribution
		/// </summary>
		public string ExpirationDate
		{
			get
			{
				object expirationDate = distribRow[SalaryDistribConstants.ExpirationDateColumnName];
				return (expirationDate==DBNull.Value)?
					string.Empty:((DateTime)expirationDate).ToString("MM/dd/yyyy");
			}
			set
			{
				distribRow[SalaryDistribConstants.ExpirationDateColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set the date on which the salary distribution was last edited
		/// Return an empty string if there is no edit date for the salary distribution
		/// </summary>
		public string EditDate
		{
			get
			{
				object editDate = distribRow[SalaryDistribConstants.EditDateColumnName];
				return (editDate==DBNull.Value)?
					string.Empty:((DateTime)editDate).ToString("MM/dd/yyyy");
			}
			set
			{
				distribRow[SalaryDistribConstants.EditDateColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set the user name of the user who last edited this salary distribution
		/// Return an empty string if there is no edit by info for the salary distribution
		/// </summary>
		public string EditedBy
		{
			get
			{
				object editedBy = distribRow[SalaryDistribConstants.EditedByColumnName];
				return (editedBy==DBNull.Value)?string.Empty:editedBy.ToString();
			}
			set
			{
				distribRow[SalaryDistribConstants.EditedByColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set the percent effort for the salary distribution
		/// Return 0 if there is no percent effort for the distribution
		/// </summary>
		public decimal PercentEffort
		{
			get
			{
				object percentEffort = distribRow[SalaryDistribConstants.PercentEffortColumnName];
				return (percentEffort==DBNull.Value)?0:(decimal)percentEffort;
			}
			set
			{
				distribRow[SalaryDistribConstants.PercentEffortColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set the project title associated with the salary distribution
		/// It is mandatory for the inheriting classes to override this property
		/// </summary>
		public abstract string Title
		{
			get;
			set;
		}
		/// <summary>
		/// Get/Set the flag representing the distribution type
		/// </summary>
		public bool IsExternalFund
		{
			get
			{
				return (bool)distribRow[SalaryDistribConstants.IsExternalFundColumnName];
			}
			set
			{
				distribRow[SalaryDistribConstants.IsExternalFundColumnName] = value;
			}
		}
		#endregion

		#region Public Contained Objects
		/// <summary>
		/// Get the distribution splits associated with the salary distribution
		/// </summary>
		public DistributionSplits Splits
		{
			get
			{
				if(splits == null)
				{
					splits = new DistributionSplits();
					splits.Load(GetSplitsDataforSalaryDistrib());
				}
				return splits;
			}
		}
		#endregion

		#region Constructor
		/// <summary>
		/// Set the dataRow to the local instance
		/// </summary>
		/// <param name="dataRow">DataRow with Salary distribution data</param>
		protected SalaryDistribution(DataRow dataRow)
		{
			distribRow = dataRow;
		}
		#endregion

		#region Instance methods (Public)
		/// <summary>
		/// Get the datarow with the data for the current instance
		/// </summary>
		/// <returns>A DataRow with the SalaryDistribution data</returns>
		public DataRow GetDataRow()
		{
			return distribRow;
		}
		/// <summary>
		/// Add a new salary distribution to the data base
		/// Throw an exception if any error in the add operation
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="domainUserID">Domain user id of the logged in user</param>
		public virtual void AddDistribution(string connectionString,int domainUserID)
		{
			try
			{
				BuildSQLParamArray(domainUserID);
				
				Utility.DataAccess.ExecuteNonQuery
					(connectionString,SalaryDistribConstants.InsertSalaryDistributionSPROCName,sqlParams);
			}
			catch(Exception ex)
			{
				throw new Exception(@"Error in adding a salary distribution.  ",ex);
			}
		}
		/// <summary>
		/// Update an existing salary distribution in the data base
		/// Throw an exception if any error in the update operation
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="domainUserID">Domain user id of the logged in user</param>
		public virtual void UpdateDistribution(string connectionString,int domainUserID)
		{
			try
			{
				BuildSQLParamArray(domainUserID);

				//Appending the DistributionID to the already built param array sqlParams
				Utility.DataAccess.AppendToSqlParameterArray(ref sqlParams,
					"@salaryDistributionID",SqlDbType.Int,DistributionID);

				Utility.DataAccess.ExecuteNonQuery
					(connectionString,SalaryDistribConstants.UpdateSalaryDistributionSPROCName,sqlParams);
			}
			catch(Exception ex)
			{
				throw new Exception(@"Error in updating salary distribution",ex);
			}
		}
		/// <summary>
		/// Delete an existing salary distribution in the database
		/// Throw an exception if any error in the delete operation
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="domainUserID">Domain user id of the logged in user</param>
		public virtual void DeleteDistribution(string connectionString,int domainUserID)
		{
			try
			{
				Utility.DataAccess.ExecuteNonQuery
					(connectionString,SalaryDistribConstants.DeleteSalaryDistributionSPROCName
					,Utility.DataAccess.BuildSqlParameterArray
					("@domainUserID",SqlDbType.Int,domainUserID
					,"@salaryDistributionID",SqlDbType.Int,DistributionID
					,"@employeeJobMapID",SqlDbType.Int,EmployeeJobMapID));
			}
			catch(Exception ex)
			{
				throw new Exception(@"Error in deleting salary distribution",ex);
			}
		}
		#endregion

		#region Private methods
		/// <summary>
		/// Get the table with the split information associated with the salary distribution
		/// </summary>
		/// <returns>A datatable with the split data for the salary distribution</returns>
		private DataTable GetSplitsDataforSalaryDistrib()
		{
			DataTable splitsTable = 
				distribRow.Table.DataSet.Tables[SplitsConstants.DistributionSplitsTableName];
			
			DataRow[] splitRows = splitsTable.Select
				(string.Format("{0}='{1}'"
				,SplitsConstants.SalaryDistributionIDColumnName
				,DistributionID.ToString()));

			DataTable splitsTableforDistribs = splitsTable.Clone();

			foreach(DataRow splitRow in splitRows)
				splitsTableforDistribs.ImportRow(splitRow);

			return splitsTableforDistribs;
		}
		/// <summary>
		/// Build the sql param array with the params which are common for both Internal and External
		/// </summary>
		/// <param name="domainUserID">Domain user id of the logged in user</param>
		private void BuildSQLParamArray(int domainUserID)
		{
			Utility.DataAccess.AppendToSqlParameterArray
				(ref sqlParams
				,"@domainUserID",SqlDbType.Int,domainUserID
				,"@employeeJobMapId",SqlDbType.Int,EmployeeJobMapID
				,"@annualRate",SqlDbType.Money,AnnualRate
				,"@comment",SqlDbType.VarChar,Comment
				,"@effectiveDate",SqlDbType.DateTime,EffectiveDate
				,"@expirationDate",SqlDbType.DateTime,ExpirationDate
				,"@modifiedBy",SqlDbType.VarChar,EditedBy
				,"@modifiedDate",SqlDbType.DateTime,EditDate
				,"@percentEffort",SqlDbType.Decimal,PercentEffort
				,"@isExternalFund",SqlDbType.Bit,IsExternalFund);
		}
		#endregion
	}
	#endregion
}